package com.kc.gb.device.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.kc.gb.device.common.adapter.StationAdaptor;
import com.kc.gb.device.common.adapter.dto.basic.rack.RackCache;
import com.kc.gb.device.common.adapter.dto.basic.rack.SimpleRackDto;
import com.kc.gb.device.common.adapter.dto.basic.slot.SlotDto;
import com.kc.gb.device.common.adapter.dto.basic.station.dto.BasicStationDTO;
import com.kc.gb.device.service.support.dto.BasicStationDetailDTO;
import com.kc.gb.device.common.adapter.dto.basic.station.dto.StationSeedingRackDTO;
import com.kc.gb.device.common.adapter.dto.wes.station.dto.StationPointDTO;
import com.kc.gb.device.common.adapter.dto.wes.station.dto.StationSlotDTO;
import com.kc.gb.device.common.adapter.dto.wes.station.dto.WesStationDTO;
import com.kc.gb.device.common.contants.CacheConst;
import com.kc.gb.device.common.dto.I18NException;
import com.kc.gb.device.common.enums.ErrorCode;
import com.kc.gb.device.common.utils.SpringHelper;
import com.kc.gb.device.common.utils.StringUtil;
import com.kc.gb.device.plugins.ptl.dto.PtlLightState;
import com.kc.gb.device.plugins.ptl.service.PtlHardwareService;
import com.kc.gb.device.service.WallPtlAdminService;
import com.kc.gb.device.service.support.dto.*;
import com.kc.gb.device.service.support.enums.VirtualType;
import com.kc.gb.feign.ptl.support.dtos.AbstractPtlCommand;
import com.kc.gb.feign.ptl.support.dtos.LedCommand;
import com.kc.gb.feign.ptl.support.dtos.LightCommand;
import com.kc.gb.feign.ptl.support.enums.PtlLedOnOff;
import com.kc.gb.feign.ptl.support.enums.PtlLightColor;
import com.kc.gb.feign.ptl.support.enums.PtlLightOnOff;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.collections.ComparatorUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.comparators.ComparableComparator;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WallPtlServiceImpl implements WallPtlAdminService {

    @Resource
    PtlHardwareService iDevicePtlService;

    @Resource
    StationAdaptor stationAdaptor;

    AtomicBoolean DEBUG_MODE = new AtomicBoolean(false);

    @Override
    public boolean changeMode(boolean isDebugMode){
        DEBUG_MODE.set(isDebugMode);
        return isDebugMode;
    }

    @Override
    public boolean getMode(){
        return DEBUG_MODE.get();
    }

    @Override
    public List<PtlLightState> getLightStates(boolean inDebugMode, List<Integer> lightNos){
        return iDevicePtlService.getLightStates(inDebugMode, lightNos);
    }

    @Override
    public void press(boolean inDebugMode, int lightNo){
        log.info("ContainerPtl|press: debugMode {},lightNo: {}", inDebugMode, lightNo);
        Assert.isTrue(ObjectUtils.isNotEmpty(iDevicePtlService),"PTL deivce not enabled");
        List<PtlLightState>  lightStates = iDevicePtlService.getLightStates(inDebugMode, Arrays.asList(lightNo));
        PtlLightState lightState = lightStates.get(0);
        log.info("ContainerPtl|lightNo:{}  state{}",  lightNo, com.alibaba.fastjson.JSON.toJSONString(lightState));
        if(inDebugMode){
            // 调试模式点亮
            if(PtlLightOnOff.LIGHT_OFF.equals(lightState.getLightStatus())){
                List<AbstractPtlCommand> commands = new ArrayList<>();
                commands.add(new LightCommand(lightNo, PtlLightOnOff.LIGHT_ON, PtlLightColor.RED,0));
                // 生成 1 到 200 之间的随机整数（包含 1 和 200）
                Random random = new Random();
                int randomNum = random.nextInt(200) + 1;
                commands.add(new LedCommand(lightNo, PtlLedOnOff.LED_ON, randomNum));
                iDevicePtlService.consumeCommands(commands,inDebugMode);
            }
            // 调试模式关灯
            else{
                List<AbstractPtlCommand> commands = new ArrayList<>();
                commands.add(new LightCommand(lightNo, PtlLightOnOff.LIGHT_OFF, PtlLightColor.RED,0));
                commands.add(new LedCommand(lightNo, PtlLedOnOff.LED_OFF, 0));
                iDevicePtlService.consumeCommands(commands,inDebugMode);
            }
        }else{
            // 模拟器模式不允许开灯操作
            if(PtlLightOnOff.LIGHT_OFF.equals(lightState.getLightStatus())){
                throw new I18NException(ErrorCode.PTL_CAN_NOT_OPEN_IN_SIMULATOR);
            }
            // 模拟器模式下关灯操作
            else{
                // 模拟拍灯事件
                iDevicePtlService.confirmed(lightNo);
                // 关灯操作
                List<AbstractPtlCommand> commands = new ArrayList<>();
                commands.add(new LightCommand(lightNo, PtlLightOnOff.LIGHT_OFF, PtlLightColor.RED,0));
                commands.add(new LedCommand(lightNo, PtlLedOnOff.LED_OFF, 0));
                iDevicePtlService.consumeCommands(commands,inDebugMode);
            }
        }
    }

    /**
     * 获取工作站料格灯的相关区域信息
     */
    @Override
    public List<StationSlotArea> getStationWallLights(Long warehouseId, String stationCode) {
        log.info("station code {}",stationCode);
/*
        BasicStationDTO basicStation = stationAdaptor.getBasicStation(warehouseId,stationCode);
        List<String> rackCodes = getStationRackCodes(basicStation);
        List<SimpleRackDto> stationRacks = stationAdaptor.getBasicRacks(warehouseId,rackCodes);
        List<SlotDto> stationSlots = stationAdaptor.getBasicSlotsByRackCode(warehouseId,rackCodes);
*/

        BasicStationDetailDTO stationDetailDTO = SpringHelper.getBean(WallPtlAdminService.class).getBasicStationDetail(warehouseId,stationCode);
        BasicStationDTO basicStation = stationDetailDTO.getStationDTO();
        List<SimpleRackDto> stationRacks = stationDetailDTO.getStationRacks();
        List<SlotDto> stationSlots = stationDetailDTO.getStationSlots();
        //
        List<SimpleRackDto> bucketDtoList = stationRacks;
        if (bucketDtoList == null) {
            return Collections.emptyList();
            //throw new StationException(StationDeviceErrorCode.STATION_HAS_NO_SLOT, stationCode);
        }
        Map<Long, List<SlotDto>> bucketSlotMap = stationSlots == null ? Maps.newHashMap()
                : stationSlots.stream().collect(Collectors.groupingBy(SlotDto::getRackId));
        // 数据封装
        //List<StationSlotDTO> stationSlotDTOS = stationAdaptor.getWesStationSlots(warehouseId,stationCode);
        List<StationSlotDTO> stationSlotDTOS = stationDetailDTO.getWesStationSlots();
        Map<String, StationSlotDTO> slotCode2SlotMap = CollectionUtils.emptyIfNull(stationSlotDTOS).stream()
                .collect(Collectors.toMap(
                        StationSlotDTO::getSlotCode,    // 键的提取器
                        slot -> slot  // 值的提取器
                ));
        // 代码迁移
        Map<String, StationSlotArea> mapSlotArea =
                bucketDtoList.stream().collect(Collectors.toMap(RackCache::getRackCode, t -> {
                    StationSlotArea slotArea = new StationSlotArea();
                    slotArea.setAreaCode(t.getRackCode());
                    slotArea.setAreaLabel(StringUtil.isBlank(t.getAlias()) ? t.getRackCode() : t.getAlias());
                    return slotArea;
                }));
        bucketDtoList.forEach(b -> {
            List<SlotDto> slotDtos = bucketSlotMap.get(b.getId());
            // 给槽位分面
            if (CollectionUtil.isNotEmpty(slotDtos)) {
                Map<Integer, List<SlotDto>> faceWithSlots = slotDtos.stream().collect(Collectors.groupingBy(SlotDto::getRackHeading));
                for (Map.Entry<Integer, List<SlotDto>> entrySet : faceWithSlots.entrySet()) {
                    List<SlotDto> currentFaceSlots = entrySet.getValue();
                    sort(currentFaceSlots, "rackLayer desc", "slotCode asc");
                    for (SlotDto slot : currentFaceSlots) {
                        StationSlotArea slotArea = mapSlotArea.get(slot.getRackCode());
                        int layer = slot.getRackLayer().intValue();
                        if (layer <= 0) {
                            continue;
                        }
                        StationSlotLayer slotLayer = slotArea.getLayer(layer);
                        if (slotLayer == null) {
                            slotLayer = new StationSlotLayer();
                            slotLayer.setLayer(layer);
                            slotArea.addLayer(slotLayer);
                        }
                        StationSlot stationSlot = new StationSlot();
                        StationSlotDTO slot2 = slotCode2SlotMap.get(slot.getSlotCode());
                        // SlotDto slot2 = slotCode2SlotMap.get(slot.getSlotCode());
                        if (slot2 == null) {
                            throw new RuntimeException();
                            /*throw new StationException(WesErrorCode.ENTITY_NOT_FOUND.getCode(),
                                    WesErrorCode.ENTITY_NOT_FOUND.getMessage(), "StationSlot",
                                    String.format("slotCode=%s", slot.getSlotCode()));*/
                        }
                        if (VirtualType.ACTUAL.getCode().equals(slot2.getVirtualType())) {
                            stationSlot.setSlotNumber(slot2.getSlotNumber());
                            stationSlot.setSlotCode(slot.getSlotCode());
                            String shortCode = StringUtil.isBlank(slot2.getSlotShortCode()) ? slot.getSlotCode(): slot2.getSlotShortCode();
                            stationSlot.setSlotShortCode(shortCode);
                            stationSlot.setEnabled(slot.getEnabled());
                            if (slot.getSlotPosition() != null) {
                                stationSlot.setX(slot.getSlotPosition().getX());
                            } else {
                                stationSlot.setX(0);
                            }

                            slotLayer.addSlot(stationSlot);
                        } else {
                            mapSlotArea.remove(slot.getRackCode());
                        }
                    }
                }
            }
        });
        // 保持排序
        final Map<String, StationSlotArea> mapAllSlotArea = new LinkedHashMap<>();
        mapAllSlotArea.putAll(mapSlotArea);
        // 加载停靠点PTL
        WesStationDTO stationDTO = stationAdaptor.getWesStationByStationCode(warehouseId,stationCode);
        if (stationDTO.getStationPoints() != null) {
            for (StationPointDTO point : stationDTO.getStationPoints()) {
                if (point.getPtlCode() != null) {
                    StationSlotArea slotArea = new StationSlotArea();
                    slotArea.setAreaCode(point.getPointCode());
                    slotArea.setAreaLabel(point.getPointCode());
                    StationSlotLayer slotLayer = new StationSlotLayer();
                    slotLayer.setLayer(1);
                    StationSlot slot = new StationSlot();
                    slot.setSlotCode(point.getPointCode());
                    slot.setSlotShortCode(point.getPointShortCode());
                    slot.setSlotNumber(point.getPtlCode());
                    slotLayer.setSlots(Lists.newArrayList(slot));
                    slotArea.setLayers(Lists.newArrayList(slotLayer));
                    mapAllSlotArea.put(point.getPointCode(), slotArea);
                }
            }
        }
        return sortStationSlotArea(Lists.newArrayList(mapAllSlotArea.values()));
    }


    /**
     * 获取工作站及绑定的货架 + 槽位信息
     * @param warehouseId
     * @param stationCode
     * @return
     */
    @Override
    @Cacheable(key = "'device:common:adapter:basic:station:detail:'+#stationCode", cacheNames = {CacheConst.Caffeine.MANAGER_3MIN})
    public BasicStationDetailDTO getBasicStationDetail(long warehouseId, String stationCode){
        BasicStationDTO stationDTO = stationAdaptor.getBasicStation(warehouseId,stationCode);
        if(stationDTO == null){
            return null;
        }
        List<StationSeedingRackDTO> racks = stationDTO.getStationSeedingRacks();
        List<String> rackCodes = CollectionUtils.emptyIfNull(racks).stream().map(StationSeedingRackDTO::getRackCode).collect(Collectors.toList());
        List<SimpleRackDto> stationRacks = stationAdaptor.getBasicRacks(warehouseId,rackCodes);
        List<SlotDto> stationSlots = stationAdaptor.getBasicSlotsByRackCode(warehouseId,rackCodes);
        List<StationSlotDTO> wesStationSlots = stationAdaptor.getWesStationSlots(warehouseId,stationCode);

        BasicStationDetailDTO detailDTO = new BasicStationDetailDTO();
        detailDTO.setStationDTO(stationDTO);
        detailDTO.setStationRacks(stationRacks);
        detailDTO.setStationSlots(stationSlots);
        detailDTO.setWesStationSlots(wesStationSlots);
        return detailDTO;
    }

    private static List<StationSlotArea> sortStationSlotArea(List<StationSlotArea> stationSlotAreas) {
        if (org.springframework.util.CollectionUtils.isEmpty(stationSlotAreas)) {
            return stationSlotAreas;
        }
        stationSlotAreas.sort(Comparator.comparing(StationSlotArea::getAreaCode));
        for (int index = 0; index < stationSlotAreas.size(); index++) {
            StationSlotArea stationSlotArea = stationSlotAreas.get(index);
            if (isLeft(index,stationSlotAreas.size())) {
                for (StationSlotLayer layer : stationSlotArea.getLayers()) {
                    layer.getSlots().sort(Comparator.comparing(StationSlot::getX).reversed());
                }
            }else {
                for (StationSlotLayer layer : stationSlotArea.getLayers()) {
                    layer.getSlots().sort(Comparator.comparing(StationSlot::getX));
                }
            }
        }
        return stationSlotAreas;
    }

    /**
     * 简单的这么判断,理论上需要根据地图或配置判断
     */
    private static boolean isLeft(int index,int totalCount){
        return index<=(totalCount-1)/2f;
    }

    public static <T> void sort(List<T> list, String... propertys) {
        if (!CollectionUtils.isEmpty(list)) {
            List<Comparator<T>> comparators = Lists.newArrayList();

            for(int i = 0; i < propertys.length; ++i) {
                String property = propertys[i];
                String[] tokens = StringUtils.split(property, " ");
                if (tokens != null && tokens.length != 0) {
                    if (tokens.length == 1) {
                        comparators.add(new BeanComparator(property, ComparableComparator.comparableComparator()));
                    } else {
                        if (tokens.length != 2) {
                            //throw new WesException(WesErrorCode.METHOD_ARGUMENT_NOT_VALID, new Object[]{"usage: sort(\"property1\", \"property2 asc\", \"property3 desc\")"});
                        }

                        if (StringUtils.equalsIgnoreCase(tokens[1], "desc")) {
                            comparators.add(new BeanComparator(tokens[0], ComparatorUtils.reversedComparator(ComparableComparator.comparableComparator())));
                        } else {
                            if (!StringUtils.equalsIgnoreCase(tokens[1], "asc")) {
                                //throw new WesException(WesErrorCode.METHOD_ARGUMENT_NOT_VALID, new Object[]{"usage: sort(\"property1\", \"property2 asc\", \"property3 desc\")"});
                            }
                            comparators.add(new BeanComparator(tokens[0], ComparableComparator.comparableComparator()));
                        }
                    }
                }
            }

            Comparator<T> chainedComparator = ComparatorUtils.chainedComparator(comparators);
            Collections.sort(list, chainedComparator);
        }
    }
}
